/**
 * FormFieldTreeEdit
 * zTree API官网：https://treejs.cn/v3/api.php
 */
layui.define(['FormField', 'yunj', 'jquery'], function (exports) {

    let FormField = layui.FormField;
    let win = window;
    let doc = document;
    let $ = layui.jquery;

    class FormFieldTreeEdit extends FormField {

        constructor(options = {}) {
            super(options);
            this.closeLevel = null;
            this.nodes = null;
            this.ztreeEl = null;
            this.ztree = null;
            this.nodeIdxMap = null;            // 节点id与对应下标的映射关系
            // 操作项属性
            this.actionRequireArgs = {
                code:"",
                type: "",
                title: '',
                class: '',
                url: '',
                confirm_form_fields:null,
                auth: '',
            };
        }

        defineExtraArgs() {
            return {
                nodes: [],
                closeLevel: 0,
                sort: "no",    // 排序。no不允许排序、yes允许排序、level允许同级别内排序
                actions: []
            };
        }

        handleArgs(args) {
            let that = this;
            // sort
            if (!args.sort) {
                args.sort = "no";
            }
            if (!["no","yes","level"].includes(args.sort)) {
                throw new Error('类型[tree]配置[sort]错误，配置值为：'+args.sort);
            }
            // actions
            that.handleArgsByActions(args);
            return args;
        }

        // 处理操作项参数
        handleArgsByActions(args) {
            let that = this;
            let actions = args.actions;
            if (!yunj.isArray(actions)) {
                actions = [];
            }
            for (let i = 0; i < actions.length; i++) {
                let action = actions[i];
                if (yunj.isString(action)) {
                    action = {code: action};
                }
                if (action.code === "rename") {
                    action = Object.assign({}, action, {
                        code: "rename",
                        title: "重命名",
                        class: "yunj-icon-rename",
                    });
                } else if (action.code === "remove") {
                    action = Object.assign({}, action, {
                        code: "remove",
                        title: "删除",
                        class: "yunj-icon-remove",
                    });
                }
                action = yunj.objSupp(action, that.actionRequireArgs);
                if (action.code.length <= 0) {
                    throw new Error(`类型[tree]配置[actions][${i}][code]不能为空`);
                }
                // 判断是否配置url
                if (action.type === 'openTab' || action.type === 'openPopup') {
                    if (!action.url) {
                        throw new Error(`类型[tree]配置[actions][${i}][type]=openTab或openPopup时，对应url不能为空`);
                    }
                }
                actions[i] = action;
            }
            args.actions = actions;
        }

        defineBoxHtml() {
            let that = this;
            return `<div class="layui-form-item yunj-form-item yunj-form-tree" id="${that.id}">__layout__</div>`;
        }

        layoutControl() {
            let that = this;
            return `<div class="layui-input-inline yunj-form-item-control"><ul id="${that.id}_ztree" class="ztree"></ul></div>`;
        }

        async renderBefore() {
            let that = this;
            that.closeLevel = that.args.closeLevel;
            if (!win.hasOwnProperty('jQuery')) {
                win.jQuery = $;
            }
            await yunj.includeCss('/static/yunj/libs/zTree_v3/css/metroStyle/metroStyle.css');
            await yunj.includeJs('/static/yunj/libs/zTree_v3/js/jquery.ztree.core.js');
            await yunj.includeJs('/static/yunj/libs/zTree_v3/js/jquery.ztree.excheck.js');
            await yunj.includeJs('/static/yunj/libs/zTree_v3/js/jquery.ztree.exedit.js');
            return 'done';
        }

        // 获取节点等级
        getNodeLevel(nodeId, nodes) {
            let that = this;
            let nodeIdxMap = that.nodeIdxMap;
            if (!nodeIdxMap.has(nodeId)) return 0;
            let idx = nodeIdxMap.get(nodeId);
            let node = nodes[idx];
            if (node.hasOwnProperty("level")) return node.level;
            if (!node.id || node.id === "0")
                node.level = 1;
            else
                node.level = that.getNodeLevel(node.id, nodes) + 1;
            return node.level;
        }

        renderDone() {
            let that = this;
            that.ztreeEl = that.boxEl.find(`#${that.id}_ztree`);
        }

        async setValue(val = '') {
            let that = this;
            let nodes = [];
            if (yunj.isArray(val)) {
                nodes = val
            } else if (yunj.isJson(val)) {
                nodes = JSON.parse(val);
            }
            if (nodes.length <= 0) {
                nodes = that.args.nodes;
            }
            nodes.forEach(node => {
                // id string
                node.id = node.id.toString();
                if (that.closeLevel > 0) {
                    let nodeLevel = that.getNodeLevel(node.id, nodes);
                    node.open = nodeLevel < that.closeLevel;
                } else {
                    node.open = true;
                }
            });
            that.nodes = nodes;
            // 初始化ztree
            that.initZtree();
        }

        // 初始化ztree
        initZtree() {
            let that = this;
            if (that.ztree) return that.ztree;
            let setting = {
                view: {
                    showIcon: false
                },
                data: {
                    key: {
                        name: "name",
                    },
                    simpleData: {
                        enable: true,
                        idKey: "id",
                        pIdKey: "pid",
                    }
                },
                edit: {
                    enable: true,
                    showRemoveBtn: false,
                    showRenameBtn: false,
                    drag: {
                        isCopy: false,
                        isMove: false,
                        prev: false,
                        inner: false,
                        next: false
                    }
                },
                callback: {
                    // 名称编辑结束
                    onRename: function (event, treeId, treeNode, isCancel) {
                        // 取消元素事件绑定并删除
                        $(`#${that.id}_ztree .yunj-tree-node-action`,that.outermostEl).unbind().remove();
                        // 设置当前最新的nodes
                        that.setCurrNodes();
                    }
                }
            };
            if (!that.args.readonly) {
                // dragSort
                that.handleZtreeSettingBySort(setting);
                // actions
                that.handleZtreeSettingByActions(setting);
            }
            that.ztree = $.fn.zTree.init(that.ztreeEl, setting, that.nodes);
        }

        // 处理ztree的setting值
        handleZtreeSettingBySort(setting) {
            let that = this;
            let sort = that.args.sort;
            // no不允许排序、yes允许排序、level允许同级别内排序
            if (sort === "yes" || sort === "level") {
                // 节点数据配置
                that.nodes.forEach((node) => {
                    // 默认都是可以拖拽排序的
                    if (!node.hasOwnProperty('drag')) {
                        node.drag = true;
                    }
                })

                // setting配置
                setting.edit.drag.isMove = true;
                setting.edit.drag.prev = true;
                setting.edit.drag.next = true;
                setting.edit.drag.inner = sort === "yes";
                // 拖拽开始前
                setting.callback.beforeDrag = function (treeId, treeNodes) {
                    // treeNodes 被拖拽的节点 JSON 数据集合
                    // 设置了drag = false的节点不允许拖拽
                    for (let i = 0, l = treeNodes.length; i < l; i++) {
                        if (treeNodes[i].drag === false) {
                            yunj.msg(`[${treeNodes[i].name}]节点禁止拖拽`);
                            return false;
                        }
                    }
                    return true;
                };
                // 拖拽结束
                setting.callback.onDrop = function (event, treeId, treeNodes, targetNode, moveType) {
                    // 设置当前最新的nodes
                    that.setCurrNodes();
                };
                // 是否仅支持同级拖拽
                if (sort === "level") {
                    // 拖拽结束前
                    setting.callback.beforeDrop = function (treeId, treeNodes, targetNode, moveType) {
                        // treeNodes 被拖拽的节点 JSON 数据集合
                        // targetNode 被拖拽放开的目标节点 JSON 数据对象

                        // 获取原始的node pid值
                        let nodeId = treeNodes[0].id;
                        let nodePids = yunj.arrayColumn(that.nodes, "pid", "id");
                        let nodePid = nodePids[nodeId] ? nodePids[nodeId].toString() : null;
                        // 获取目标的node pid值
                        let targetNodePid = targetNode && targetNode.pid ? targetNode.pid.toString() : null;
                        // 不是同级则弹出提示
                        if (nodePid !== targetNodePid) {
                            yunj.msg('当前仅允许同级排序');
                            return false;
                        }
                        return true;
                    }
                }
            }
        }

        // 处理ztree的setting值
        handleZtreeSettingByActions(setting) {
            let that = this;
            let actions = that.args.actions;
            if (actions.length <= 0) {
                return;
            }
            // 鼠标移动到节点上时，显示用户自定义控件
            setting.view.addHoverDom = function (treeId, treeNode) {
                if (treeNode.hasOwnProperty("readonly") && treeNode.readonly) {
                    return;
                }
                let nodeEl = $("#" + treeNode.tId + "_a",that.outermostEl);
                if (nodeEl.find('.yunj-tree-node-action').length > 0) {
                    return;
                }
                let nodeActions = [];
                let events = treeNode.events;
                if (events) {
                    if (yunj.isJson(events)) {
                        events = JSON.parse(events);
                    } else if (yunj.isString(events) && events.indexOf(',') !== -1) {
                        events = events.split(',');
                    }
                    events = yunj.isArray(events) ? events : [events];
                }
                events = yunj.isArray(events) ? events : [];
                if (events.length > 0) {
                    let actionObjs = yunj.arrayColumn(actions, null, 'code');
                    treeNode.events.forEach(event => {
                        if (actionObjs.hasOwnProperty(event)) {
                            nodeActions.push(actionObjs[event]);
                        }
                    });
                } else {
                    nodeActions = actions;
                }
                let actionsHtml = '';
                nodeActions.forEach(action => {
                    actionsHtml += `<span class="yunj-tree-node-action" id="${that.id}_${action.code}" title="${action.title}" data-args="${encodeURIComponent(JSON.stringify(action))}">
                                        ${action.class ? `<i class="${yunj.iconClass(action.class)}"></i>` : action.title}
                                    </span>`;
                });
                nodeEl.append(actionsHtml);
                // 事件绑定
                $(`#${that.id}_ztree .yunj-tree-node-action`,that.outermostEl).bind('click', function (e) {
                    let btnEl = $(this);
                    let args = JSON.parse(decodeURIComponent(btnEl.data('args')));

                    

                    if (args.confirm_form_fields && yunj.isArray(args.confirm_form_fields) && args.confirm_form_fields.length > 0) {
                        yunj.confirmForm({
                            formId: `yunj_tree_edit_confirm_form_${that.id}`,
                            fields:args.confirm_form_fields,
                            yes:(data)=>{
                                // 获取确认表单数据
                                args.confirmFormData = data;
                                that.handleEditEvent(treeNode, args);
                            }
                        });
                    } else {
                        that.handleEditEvent(treeNode, args);
                    }
                    e.stopPropagation();
                });
            };
            // 鼠标移出节点时，隐藏用户自定义控件
            setting.view.removeHoverDom = function (treeId, treeNode) {
                // 取消元素事件绑定并删除
                let actionEl = $(`#${that.id}_ztree .yunj-tree-node-action`,that.outermostEl);
                actionEl.length > 0 && actionEl.unbind().remove();
            };
        }

        /**
         * 处理事件
         * @param {object} treeNode 事件节点
         * @param {object} args     事件参数
         */
        handleEditEvent(treeNode, args) {
            let that = this;
            let code = args.code;
            switch (args.type) {
                case 'openPopup':
                    let popupParam = {id: treeNode.id};
                    let popupTitle = args.title + ':' + treeNode.name;
                    yunj.openPopup(yunj.handlePageUrl(yunj.urlPushParam(args.url, popupParam)), popupTitle);
                    break;
                case 'openTab':
                    let tabParam = {id: treeNode.id};
                    let tabTitle = args.title + ':' + treeNode.name;
                    yunj.openTab(yunj.handlePageUrl(yunj.urlPushParam(args.url, tabParam)), tabTitle);
                    break;
                case 'asyncEvent':
                    let requestData = {
                        event: code,
                        id: treeNode.id,
                        name: treeNode.name,
                        pid: treeNode.pid
                    };
                    yunj.request({
                        url: args.url ? args.url : that.url,
                        data: requestData,
                        type: 'post',
                        loading: true
                    }).then(res => {
                        that.outermostEl.trigger(`yunj_tree_${that.id}_async_event_done`, [code, treeNode, requestData, res]);
                    }).catch(e => {
                        yunj.error(e);
                    });
                    break;
                default:
                    // 触发前端事件
                    switch (code) {
                        // 重命名
                        case 'rename':
                            that.ztree.editName(treeNode);
                            break;
                        // 删除
                        case 'remove':
                            that.ztree.removeNode(treeNode);
                            // 设置当前最新的nodes
                            that.setCurrNodes();
                            break;
                    }
                    that.outermostEl.trigger(`yunj_tree_${that.id}_${code}`, [treeNode]);
            }
        }

        // 设置当前所有节点数据
        setCurrNodes(nodes = []) {
            let that = this;
            let currNodes = [];
            let rawNodesLen = nodes.length;
            if (rawNodesLen <= 0) {
                nodes = that.ztree.getNodes();
            }
            nodes.forEach((node) => {
                currNodes.push(that.handleNode(node));
                if (node.hasOwnProperty('children') && node.children.length > 0) {
                    currNodes.push(...that.setCurrNodes(node.children));
                }
            });
            if (rawNodesLen <= 0 && currNodes.length >= 0) {
                that.nodes = currNodes;
            }
            return currNodes;
        }

        // 处理单个节点数据
        handleNode(node) {
            let that = this;
            return {
                id: node.id,
                pid: node.pid,
                name: node.name,
                drag: node.drag
            };
        }

        getValue() {
            let that = this;
            let val = [];
            if (that.nodes && that.nodes.length > 0) {
                that.nodes.forEach(node => {
                    val.push({
                        id: node.id,
                        name: node.name,
                        pid: node.pid
                    });
                });
            }
            return val;
        }

        defineExtraEventBind() {
            let that = this;

        }

    }

    exports('FormFieldTreeEdit', FormFieldTreeEdit);
});